package com.yonyou.pmclouds.mob.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yonyou.iuap.tenant.sdk.TenantCenter;
import com.yonyou.pmclouds.ApplicationConsts;
import com.yonyou.pmclouds.basecom.conf.DeployTypeConfiguration;
import com.yonyou.pmclouds.basecom.conf.ExperInfoProperties;
import com.yonyou.pmclouds.basecom.entity.PageObject;
import com.yonyou.pmclouds.basecom.exception.BusinessException;
import com.yonyou.pmclouds.basecom.util.CommonProgramConsts;
import com.yonyou.pmclouds.basecom.util.RSAUtil;
import com.yonyou.pmclouds.experuser.entity.ExperUserVO;
import com.yonyou.pmclouds.experuser.rmiitf.ExperUserRemoteMobService;
import com.yonyou.pmclouds.outter.enterprise.EnterpriseOperator;
import com.yonyou.pmclouds.outter.role.RoleInfoQuery;
import com.yonyou.pmclouds.outter.tenant.TenantOperator;
import com.yonyou.pmclouds.outter.user.UserInfoQuery;
import com.yonyou.pmclouds.outter.user.UserOperator;
import com.yonyou.pmclouds.project.entity.ProjectConst;
import com.yonyou.pmclouds.project.entity.ProjectVO;
import com.yonyou.pmclouds.project.rmiitf.ProjectSimpleQuery;
import com.yonyou.pmclouds.team.entity.TeamMemberVO;
import com.yonyou.pmclouds.team.entity.TeamMemberVO.UserRoleConst;
import com.yonyou.pmclouds.team.rmiitf.ProjectRefWithTeamQuery;
import com.yonyou.pmclouds.team.rmiitf.TeamMemberMaintain;
import com.yonyou.pmclouds.user.entity.UserInfo;
import com.yonyou.yht.sdk.UserCenter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.*;

/**
 * 移动端登录
 *
 * @author zhangwce
 */
@Slf4j
@Controller
@RequestMapping(value = "/mobile/mobLogin")
public class MobLoginController {

    @Reference(version = ApplicationConsts.APPLICATION_VERSION)
    private TeamMemberMaintain teamMemberMaintain;
    @Reference(version = ApplicationConsts.APPLICATION_VERSION)
    private ProjectRefWithTeamQuery projectRefWithTeamQuery;
    @Reference(version = ApplicationConsts.APPLICATION_VERSION)
    private ProjectSimpleQuery projectSimpleQuery;
    @Reference(version = ApplicationConsts.APPLICATION_VERSION)
    private ExperUserRemoteMobService experUserRemoteMobService;

    @Autowired
    private ExperInfoProperties experInfoProperties;

    @Autowired
    private EnterpriseOperator enterpriseOperator;
    @Autowired
    private TenantOperator tenantOperator;
    @Autowired
    private UserOperator userOperator;
    @Autowired
    private UserInfoQuery userInfoQuery;
    @Autowired
    private RoleInfoQuery roleInfoQuery;

    // 判断是否为专属云部署，如为专属云部署，禁用掉体验功能
    @Autowired
    private DeployTypeConfiguration.DeployInfo deployInfo;


    private ObjectMapper objectMapper = new ObjectMapper();
    private static final String EXPERIENCE_LOGIN = "experience_login";
    private static final String FORMAL_LOGIN = "formal_login";
    private static final String NOTENANT_LOGIN = "notenant_login";
    // 配置文件中的角色与表中应存储的值得对应关系
    private static Map<String, Byte> roleMap;

    @RequestMapping(value = "/login")
    @ResponseBody
    public Object mobLogin(@RequestParam("username") String username, @RequestParam("password") String password) throws BusinessException {

        if (username == null || password == null) {
            log.error("登录失败：用户名密码为空");
            return "用户名密码为空";
        }

        String tokenInfo = UserCenter.generateAccessToken(username, RSAUtil.decrypt(password.replaceAll("%2B", "+")),
                true);
        log.warn("登录结果：" + tokenInfo);
        if (StringUtils.isEmpty(tokenInfo))
            throw new BusinessException("登录出错：友户通生成token服务异常");

        Map resultMap = null;
        try {
            resultMap = objectMapper.readValue(tokenInfo, Map.class);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        // 烂代码，没办法
        if (Integer.valueOf(0).equals(resultMap.get("status"))) {// 登录失败
            String msg = "用户名或密码错误";
            if (resultMap.get("msg") != null) {
                msg = (String) resultMap.get("msg");
                if (msg.contains("not fount the user")) {
                    msg = "用户不存在";
                } else if (msg.contains("用户被锁定")) {
                    msg = "用户被锁定";
                } else {
                    msg += ",6次后用户将会被锁定";
                }
            }
            throw new BusinessException(msg);
        }

        String userInfo = UserCenter.getUserByToken((String) (((Map) resultMap.get("data")).get("access_token")));
        if(StringUtils.isEmpty(userInfo))
            throw new BusinessException("根据token获取用户信息出错:友户通服务异常");

        String userId = null;
        Map userMap = null;
        try {
            userMap = objectMapper.readValue(userInfo, Map.class);
            resultMap.put("username", ((Map) userMap.get("user")).get("userName"));
            userId = (String) (((Map) userMap.get("user")).get("userId"));
            resultMap.put("userid", userId);

        } catch (Exception e) {
            log.error(e.getMessage());
        }

        if (StringUtils.isEmpty(userId))
            throw new BusinessException("根据token获取用户信息出错");

        // 检查用户是否有可登录的数据中心，以及是否是体验登录
        String checkResult = getCanLoginTenant(userId);

        switch (checkResult) {
            case NOTENANT_LOGIN :
               if(!isNeedExper()){
                    throw new BusinessException("没有可以登录的数据中心");
                }

                List<ExperUserVO> experUserList = experUserRemoteMobService.queryExperUserByUserId(userId);

                if(experUserList == null || experUserList.size() == 0){
                    resultMap.put("team_check_result", "unRelated");
                }else{
                    if(checkOverTime(experUserList.get(0)))
                        throw new BusinessException("没有可以登录的数据中心");
                    // 体验表中有记录，但是人员已经从体验租户里踢出，则再次加入租户。（团队分配信息并未删除，因此只加入租户即可）
                    // 将用户加入到体验数据中心
                    if(username.contains("@")){// 暂用这种方式区分是邮箱登录还是手机号登录
                        addUserToTenant(null, username);
                    }else{
                        addUserToTenant(username, null);
                    }

                }

                break;
            case EXPERIENCE_LOGIN :
                if(isNeedExper()){
                    checkExperPeriod(userId);
                }
                break;
            case FORMAL_LOGIN  :
                break;

        }

        return resultMap;
    }

    /**
     * 方法功能描述：检查用户是否在体验期内。
     * <p>
     * <b>参数说明</b>
     *
     * @param userId
     * @throws BusinessException
     * @author zhangwce
     * @time 2018年1月23日 下午2:25:46
     */
    private void checkExperPeriod(String userId) throws BusinessException {
        List<ExperUserVO> experUserList = experUserRemoteMobService.queryExperUserByUserId(userId);
        if(experUserList != null && experUserList.size() > 0){
            ExperUserVO experUserVO = experUserList.get(0);

            if(checkOverTime(experUserVO)){
                throw new BusinessException("用户体验期已过");
            }
        }
    }

    /**
     * 检测超期
     * @param experUserVO
     * @return
     * @throws BusinessException
     */
    private boolean checkOverTime(ExperUserVO experUserVO) throws BusinessException{

        Date createtime = experUserVO.getCreationtime();
        Date currtime = new Date();

        int days = (int) ((currtime.getTime() - createtime.getTime()) / (1000 * 3600 * 24));
        if (days > Integer.valueOf(experInfoProperties.getExper_period()))
            return true;
        return false;

    }

    /**
     * 方法功能描述：检查体验用户是否已经关联到项目团队。
     * <p>
     * <b>参数说明</b>
     *
     * @param resultMap
     * @param userId
     * @throws BusinessException
     * @author zhangwce
     * @time 2018年1月21日 下午10:27:43
     */
    private void checkTeamRelated(Map resultMap, String userId) throws BusinessException {

        // 判断用户有没有加入项目团队
        PageObject canLoginPro = projectRefWithTeamQuery.queryOfUser(userId,
                experInfoProperties.getPk_exper_tenant(), null, 0, CommonProgramConsts.DEFAULT_MAX_QUERY_SIZE, null);

        if (canLoginPro.getObjects() == null || canLoginPro.getObjects().length == 0) {
            resultMap.put("team_check_result", "unRelated");
        } else {
            resultMap.put("team_check_result", "related");
        }
    }

    /**
     * 给体验用户授权
     * <p>
     * <b>参数说明</b>
     *
     * @return
     * @author zhangwce
     * @time 2018年1月19日 下午3:07:20
     */
    @RequestMapping(value = "/authExperUser")
    @ResponseBody
    public Object authExperUser(@RequestParam String userId, @RequestParam String teamRole) throws BusinessException {

        Date authBeginDate = new Date();

        // 根据联系方式获取用户ID
        UserInfo userInfo = userInfoQuery.queryUser(userId);

        if (userInfo == null)
            throw new BusinessException("获取用户出错");

        // 获得该用户有PMC应用权限的数据中心
        List<Map> canTenantList = getPMCTenant(userInfo.getUserId());

        if (canTenantList == null || canTenantList.size() == 0) {
            Date saveExperBeginDate = new Date();
            // 将体验用户信息保存到本地
            saveExperUserToLocal(userInfo);
            log.error("将体验用户信息保存到本地,总耗时：" + (new Date().getTime() - saveExperBeginDate.getTime()));
        }
        Date addToEnterDate = new Date();
        // 将用户加入到体验企业
        addUserToEnter(userId, teamRole);
        log.error("将用户加入到体验企业,总耗时：" + (new Date().getTime() - addToEnterDate.getTime()));

        Date addToTenantDate = new Date();
        // 将用户加入到体验数据中心
        addUserToTenant(userInfo.getUserMobile(), userInfo.getUserEmail());
        log.error("将用户加入到体验企业,总耗时：" + (new Date().getTime() - addToTenantDate.getTime()));

        Date addRoleDate = new Date();
        // 为体验用户分配角色
        userAddRole(userId, teamRole);
        log.error("为体验用户分配角色,总耗时：" + (new Date().getTime() - addRoleDate.getTime()));

        Date addToTeamDate = new Date();
        // 将体验用户加入到项目团队
        addUserToProTeam(userId, teamRole);
        log.error("体验用户加入项目团队,总耗时：" + (new Date().getTime() - addToTeamDate.getTime()));

        log.error("授权方法总耗时：" + (new Date().getTime() - authBeginDate.getTime()));

        return true;
    }

    /**
     * 方法功能描述：获得包含PMC应用的数据中心。
     * <p>
     * <b>参数说明</b>
     *
     * @param userId
     * @return
     * @throws BusinessException
     * @author zhangwce
     * @time 2018年1月25日 上午11:09:47
     */
    private List<Map> getPMCTenant(String userId) throws BusinessException {
        // 判断用户是否有包含PMC的数据中心
        String canLoginResult = TenantCenter.getCanLoginTenants(userId, DeployTypeConfiguration.getSysId());
        if (StringUtils.isEmpty(canLoginResult))
            throw new BusinessException("获取用户可登录本应用的企业中心出错：友户通服务异常");
        Map tenantMap = null;
        try {
            tenantMap = objectMapper.readValue(canLoginResult, Map.class);
        } catch (Exception e) {
            log.error(e.getMessage());
        }

        if (Integer.valueOf(0).equals(tenantMap.get("status"))) {
            log.error("获取用户可登录本应用的数据中心错误，错误信息为：" + tenantMap.get("msg"));
            throw new BusinessException("获取用户应用权限信息失败");
        }

        List<Map> canTenantList = (ArrayList<Map>) tenantMap.get("tenants");
        return canTenantList;
    }

    /**
     * 方法功能描述：添加用户到体验数据中心。
     * <p>
     * <b>参数说明</b>
     *
     * @param mobile
     * @param email
     * @throws BusinessException
     * @author zhangwce
     * @time 2018年1月22日 下午1:51:53
     */
    private void addUserToTenant(String mobile, String email) throws BusinessException {
        String tenantId = experInfoProperties.getPk_exper_tenant();
        // 将用户加入体验数据中心
        tenantOperator.addUsersAndRelations(tenantId, mobile, email);
    }

    /**
     * 方法功能描述：添加用户到体验企业账号。
     * <p>
     * <b>参数说明</b>
     *
     * @param userId
     * @throws BusinessException
     * @author zhangwce
     * @time 2018年1月22日 下午1:50:56
     */
    private void addUserToEnter(String userId, String teamRole) throws BusinessException {

        String pk_exper_enterprise = experInfoProperties.getTeam_role_info().get(teamRole).get("pk_exper_enterprise");

        // 将用户加入到体验中心
        enterpriseOperator.userApplyJoinEnter(userId, pk_exper_enterprise);
    }

    /**
     * 方法功能描述：保存体验用户信息。
     * 登录时保存体验用户信息，是为了针对在web端注册了友户通账号，但是没有PMC应用的情况，需要把这部分数据信息记录到本地
     * <p>
     * <b>参数说明</b>
     *
     * @param userInfo
     *
     * @throws BusinessException
     * @author zhangwce
     * @time 2018年1月22日 下午2:59:46
     */
    private void saveExperUserToLocal(UserInfo userInfo) throws BusinessException {
        ExperUserVO experUserVO = new ExperUserVO();
        experUserVO.setUserid(userInfo.getUserId());
        experUserVO.setUser_name(userInfo.getUserName());
        experUserVO.setMobile(userInfo.getUserMobile());
        experUserVO.setEmail(userInfo.getUserEmail());

        // 保存体验用户，服务内会根据userId校验，同一个用户的数据不会重复保存。
        experUserRemoteMobService.addExperUser(experUserVO);
    }

    /**
     * 方法功能描述：将体验用户加入到项目团队。
     * <p>
     * <b>参数说明</b>
     *
     * @param userId
     * @param teamRole
     * @throws BusinessException
     * @author zhangwce
     * @time 2018年1月21日 下午10:52:39
     */
    private void addUserToProTeam(String userId, String teamRole) throws BusinessException {
        // 根据teamRole来决定所要绑定到的企业
        String pk_enterprise = getExperEnterprise(teamRole);

        // 查询到体验租户下的所有项目
        ProjectVO[] experPros = projectSimpleQuery.queryProjectByTenant(experInfoProperties.getPk_exper_tenant(),
                ProjectConst.STATE_GOING);

        if (experPros != null && experPros.length > 0) {

            List<TeamMemberVO> memberList = new ArrayList<TeamMemberVO>();

            for (ProjectVO projectVO : experPros) {
                TeamMemberVO memberVO = new TeamMemberVO();

                memberVO.setPkUser(userId);
                memberVO.setPkTenant(experInfoProperties.getPk_exper_tenant());

                memberVO.setUserRole(getUserRoleMap().get(teamRole));
                memberVO.setPkProject(projectVO.getPkProject());
                memberVO.setPkEnterprise(pk_enterprise);

                memberList.add(memberVO);
            }

            if (memberList != null && memberList.size() > 0) {
                teamMemberMaintain.addMembers(memberList.toArray(new TeamMemberVO[0]));
            }

        }
    }

    /**
     * 方法功能描述：获取角色的对应关系。
     * <p>
     * <b>参数说明</b>
     *
     * @return
     * @author zhangwce
     * @time 2018年1月25日 下午10:06:49
     */
    private Map<String, Byte> getUserRoleMap() {

        if (roleMap == null) {
            roleMap = new HashMap<String, Byte>();
            roleMap.put("role_constructor", UserRoleConst.ROLE_CONSTRUCTOR);
            roleMap.put("role_owner", UserRoleConst.ROLE_OWNER);
            roleMap.put("role_supervisor", UserRoleConst.ROLE_SUPERVISOR);
        }

        return roleMap;
    }

    /**
     * 方法功能描述：根据选择的团队角色获取体验企业的ID。
     * <p>
     * <b>参数说明</b>
     *
     * @param teamRole
     * @return
     * @author zhangwce
     * @time 2018年1月22日 上午11:35:40
     */
    private String getExperEnterprise(String teamRole) {
        return experInfoProperties.getTeam_role_info().get(teamRole).get("pk_exper_enterprise");
    }

    /**
     * 方法功能描述: 为体验用户分配角色。
     * <p>
     * <b>参数说明</b>
     *
     * @param userId
     * @param teamRole
     * @throws BusinessException
     * @author zhangwce
     * @time 2018年1月21日 下午10:47:24
     */
    private void userAddRole(String userId, String teamRole) throws BusinessException {

        // 获取体验用户的角色
        List<Map> roleMapList = getExperRole(teamRole);

        if (roleMapList == null || roleMapList.size() == 0) {
            throw new BusinessException("尚未预制体验角色");
        }

        userOperator.userAddRole(userId, experInfoProperties.getPk_exper_tenant(), roleMapList);

    }

    /**
     * 方法功能描述：获取体验用户的角色。
     * <p>
     * <b>参数说明</b>
     *
     * @param teamRole
     * @return
     * @throws BusinessException
     * @author zhangwce
     * @time 2018年1月21日 下午10:44:49
     */
    private List<Map> getExperRole(String teamRole) throws BusinessException {
        // 获取团队角色对应的用户角色列表
        List<String> roleCodeList = getRoleCodeList(teamRole);

        if (roleCodeList == null || roleCodeList.size() == 0)
            return null;

        // 获取工程云体验数据中心下的所有角色
        List roleResultList = roleInfoQuery.queryRolesByTenant(experInfoProperties.getPk_exper_tenant());

        if (roleResultList == null || roleResultList.size() == 0)
            return null;

        List<Map> roleMapList = new ArrayList<Map>();

        String roleCode = null;
        String roleId = null;
        for (Object roleMap : roleResultList) {
            roleCode = ((Map) roleMap).get("roleCode") == null ? "" : (String) ((Map) roleMap).get("roleCode");
            roleId = ((Map) roleMap).get("roleId") == null ? "" : (String) ((Map) roleMap).get("roleId");

            if (roleCodeList.contains(((Map) roleMap).get("roleCode"))) {
                Map<String, String> map = new HashMap<String, String>();
                map.put("roleId", roleId);
                map.put("roleCode", roleCode);

                roleMapList.add(map);
            }

        }
        return roleMapList;
    }

    /**
     * 方法功能描述：获取团队角色对应的用户角色列表。
     * <p>
     * <b>参数说明</b>
     *
     * @param teamRole
     * @author zhangwce
     * @time 2018年1月22日 上午11:28:15
     */
    private List<String> getRoleCodeList(String teamRole) {
        Map<String, String> teamRoleInfo = experInfoProperties.getTeam_role_info().get(teamRole);

        List<String> roleCodeList = new ArrayList<String>();
        roleCodeList.add(teamRoleInfo.get("role_code"));

        return roleCodeList;
    }

    /**
     * 方法功能描述：检验该用户是否有可登陆工程云的租户。
     * <p>
     * <b>参数说明</b>
     *
     * @param userId
     * @throws BusinessException
     * @author zhangwce
     * @time 2017年12月7日 上午11:34:17
     */
    private String getCanLoginTenant(String userId) throws BusinessException {
        List<Map> canTenantList = getPMCTenant(userId);
        if (canTenantList == null || canTenantList.size() == 0) {
            return NOTENANT_LOGIN;
        }
        if (canTenantList.size() == 1 && experInfoProperties.getPk_exper_tenant().equals(canTenantList.get(0).get("tenantId"))) {// 判断当前用户是否只属于工程云体验数据中心
            return EXPERIENCE_LOGIN;
        } else {
            return FORMAL_LOGIN;
        }

    }

    @RequestMapping(value = "/refreshToken")
    @ResponseBody
    public String refreshToken(@RequestParam String refresh_token) throws BusinessException {

        if (refresh_token == null || "".equals(refresh_token)) {
            log.error("刷新token失败：refresh_token为空");
            return "refresh_token为空";
        }

        String result = UserCenter.refreshAccessToken(refresh_token);

        Map resultMap = null;
        try {
            resultMap = objectMapper.readValue(result, Map.class);
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (Integer.valueOf(0).equals(resultMap.get("status"))) {// 登录失败
            throw new BusinessException(resultMap.get("msg") == null ? "" : (String) resultMap.get("msg"));
        }

        return UserCenter.refreshAccessToken(refresh_token);
    }

    /**
     * 是否需要体验功能
     *
     * @return
     */
    private boolean isNeedExper() {
        return DeployTypeConfiguration.DeployInfo.PUBLIC_DEPLOY.equals(deployInfo.getDeployType());
    }

}
